package com.nwpu.server.authserver.controller;

import cn.hutool.core.util.ObjectUtil;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import com.nwpu.server.authserver.annotation.OperationLogAspect;
import com.nwpu.server.authserver.entity.UserEntity;
import com.nwpu.server.authserver.exception.EmailException;
import com.nwpu.server.authserver.exception.UsernameException;
import com.nwpu.server.authserver.service.CaptchaService;
import com.nwpu.server.authserver.service.UserService;
import com.nwpu.server.authserver.service.UserTokenService;
import com.nwpu.server.authserver.vo.LoginForm;
import com.nwpu.server.authserver.vo.PasswordForm;
import com.nwpu.server.authserver.vo.RegisterForm;
import com.nwpu.server.common.exception.BizCodeEnum;
import com.nwpu.server.common.response.PageUtils;
import com.nwpu.server.common.response.R;
import com.nwpu.server.common.valid.LoginGroup;
import com.nwpu.server.common.valid.RegisterGroup;
import com.nwpu.server.common.valid.UpdateUserGroup;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Map;


/**
 * 用户
 *
 * @author YuXingZh
 * @email 617058979@qq.com
 * @date 2022-03-13 16:29:47
 */
@CrossOrigin
@RestController
@RequestMapping("authserver/user")
public class UserController extends AbstractController {
    @Autowired
    UserService userService;

    @Autowired
    CaptchaService captchaService;

    @Autowired
    UserTokenService userTokenService;



    @PostMapping(value = "/register")
    @OperationLogAspect(module = "user", description = "注册", value = "注册")
    public R register(@Validated(RegisterGroup.class) @RequestBody RegisterForm vo) {
        if (ObjectUtil.isNull(vo.getEmail())) {
            return R.error(BizCodeEnum.USER_ERROR_A0153.getCode(), BizCodeEnum.USER_ERROR_A0153.getMsg());
        }

        if (ObjectUtil.isNull(vo.getPhone())) {
            return R.error(BizCodeEnum.USER_ERROR_A0151.getCode(), BizCodeEnum.USER_ERROR_A0151.getMsg());
        }

        if (ObjectUtil.isNull(vo.getUsername())) {
            return R.error(BizCodeEnum.USER_ERROR_A0110.getCode(), BizCodeEnum.USER_ERROR_A0110.getMsg());
        }

        if (ObjectUtil.isNull(vo.getPassword())) {
            return R.error(BizCodeEnum.USER_ERROR_A0120.getCode(), BizCodeEnum.USER_ERROR_A0120.getMsg());
        }

        try {
            userService.register(vo);
        } catch (EmailException e) {
            return R.error(BizCodeEnum.EMAIL_EXIST_EXCEPTION.getCode(), BizCodeEnum.EMAIL_EXIST_EXCEPTION.getMsg());
        } catch (UsernameException e) {
            return R.error(BizCodeEnum.USER_EXIST_EXCEPTION.getCode(), BizCodeEnum.USER_EXIST_EXCEPTION.getMsg());
        }

        return R.ok();
    }


    @PostMapping(value = "/login")
    @OperationLogAspect(module = "user", description = "登录", value = "登录")
    public R login(@Validated(LoginGroup.class) @RequestBody LoginForm form) {

        // 校验验证码
        boolean captcha = captchaService.validate(form.getUuid(), form.getCaptcha());
        if (!captcha) {
            return R.error(BizCodeEnum.CAPTCHA_EXCEPTION.getCode(), BizCodeEnum.CAPTCHA_EXCEPTION.getMsg());
        }

        //用户信息
        UserEntity user = userService.login(form);

        //账号不存在、密码错误
        if (user == null) {
            return R.error(BizCodeEnum.USER_NONEXIST_EXCEPTION.getCode(), BizCodeEnum.USER_NONEXIST_EXCEPTION.getMsg());
        }

        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        //进行密码匹配
        if (!passwordEncoder.matches(form.getPassword(), user.getPassword())) {
            return R.error(BizCodeEnum.LOGINACCT_PASSWORD_EXCEPTION.getCode(), BizCodeEnum.LOGINACCT_PASSWORD_EXCEPTION.getMsg());
        }

        //账号锁定
        if (user.getStatus() == 0) {
            return R.error(BizCodeEnum.USER_LOCK_EXCEPTION.getCode(), BizCodeEnum.USER_LOCK_EXCEPTION.getMsg());
        }

        //生成token，并保存到数据库
        R r = userTokenService.createToken(user.getUserId(), user.getUsername(), user.getPassword());
        r.put("user_id", user.getUserId());
        return r;
    }

    /**
     * 列表
     */
    @RequestMapping("/list")
    public R list(@RequestParam Map<String, Object> params) {
        PageUtils page = userService.queryPage(params);

        return R.ok().put("page", page);
    }


    /**
     * 获取登录的用户信息
     */
    @GetMapping("/info")
    public R info() {
        return R.ok().put("user", getUser());
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
    public R save(@RequestBody UserEntity user) {
        userService.save(user);

        return R.ok();
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    public R update(@RequestBody UserEntity user) {
        userService.updateById(user);

        return R.ok();
    }

    /**
     * 验证码
     */
    @RequestMapping(value = "/captcha.jpg", method= RequestMethod.GET)
    public void captcha(HttpServletResponse response, @RequestParam("uuid") String uuid) throws ServletException, IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");

        //获取图片验证码
        BufferedImage image = captchaService.getCaptcha(uuid);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
        IOUtils.closeQuietly(out);
    }

    /**
     * 修改登录用户密码
     */
    @PostMapping("/password")
    @OperationLogAspect(module = "user", description = "修改密码", value = "修改密码")
    public R password(@Validated(UpdateUserGroup.class) @RequestBody PasswordForm form) {
        // 校验密码不能为空

        //sha256加密
        String password = new Sha256Hash(form.getPassword(), getUser().getSalt()).toHex();
        //sha256加密
        String newPassword = new Sha256Hash(form.getNewPassword(), getUser().getSalt()).toHex();

        //更新密码
        boolean flag = userService.updatePassword(getUserId(), password, newPassword);
        if (!flag) {
            return R.error("原密码不正确");
        }

        return R.ok();
    }

}
